// optional standard header
// Copyright (c) Microsoft Corporation. All rights reserved.
#pragma once
#ifndef _OPTIONAL_
#define _OPTIONAL_
#ifndef RC_INVOKED
#include <yvals.h>

#if _HAS_CXX17
#include <exception>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <xmemory0>
#include <xsmf_control.h>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN

// STRUCT nullopt_t [optional.nullopt]
struct nullopt_t { // no-value state indicator
    struct _Tag {};
    constexpr explicit nullopt_t(_Tag) {}
};
inline constexpr nullopt_t nullopt{nullopt_t::_Tag{}};

// CLASS bad_optional_access [optional.bad_optional_access]
class bad_optional_access : public exception {
public:
    _NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept override {
        return "Bad optional access";
    }

#if !_HAS_EXCEPTIONS
protected:
    virtual void _Doraise() const { // perform class-specific exception handling
        _RAISE(*this);
    }
#endif // !_HAS_EXCEPTIONS
};

template <class _Ty,
    bool = is_trivially_destructible_v<_Ty>>
struct _Optional_destruct_base { // either contains a value of _Ty or is empty (trivial destructor)
    union {
        char _Dummy;
        remove_const_t<_Ty> _Value;
    };
    bool _Has_value;

    constexpr _Optional_destruct_base() noexcept : _Dummy{}, _Has_value{false} { // initialize an empty optional
    }

    template <class... _Types>
    constexpr explicit _Optional_destruct_base(in_place_t, _Types&&... _Args)
        : _Value(_STD forward<_Types>(_Args)...), _Has_value{true} { // initialize contained value with _Args...
    }

    void reset() noexcept { // destroy any contained value and transition to the empty state
        this->_Has_value = false;
    }
};

template <class _Ty>
struct _Optional_destruct_base<_Ty, false> { // either contains a value of _Ty or is empty (non-trivial destructor)
    union {
        char _Dummy;
        remove_const_t<_Ty> _Value;
    };
    bool _Has_value;

    ~_Optional_destruct_base() noexcept { // destroy any contained value
        if (_Has_value) {
            _Destroy_in_place(_Value);
        }
    }

    constexpr _Optional_destruct_base() noexcept : _Dummy{}, _Has_value{false} { // initialize an empty optional
    }

    template <class... _Types>
    constexpr explicit _Optional_destruct_base(in_place_t, _Types&&... _Args)
        : _Value(_STD forward<_Types>(_Args)...), _Has_value{true} { // initialize contained value with _Args...
    }

    _Optional_destruct_base(const _Optional_destruct_base&) = default;
    _Optional_destruct_base(_Optional_destruct_base&&)      = default;
    _Optional_destruct_base& operator=(const _Optional_destruct_base&) = default;
    _Optional_destruct_base& operator=(_Optional_destruct_base&&) = default;

    void reset() noexcept { // destroy any contained value and transition to the empty state
        if (this->_Has_value) {
            _Destroy_in_place(this->_Value);
            this->_Has_value = false;
        }
    }
};

template <class _Ty>
struct _Optional_construct_base
    : _Optional_destruct_base<_Ty> { // Layer common behaviors atop the _Optional_destruct_base implementations
    using _Optional_destruct_base<_Ty>::_Optional_destruct_base;

    template <class... _Types>
    _Ty& _Construct(_Types&&... _Args) { // transition from the empty to the value-containing state
                                         // pre: !this->_Has_value
        _Construct_in_place(this->_Value, _STD forward<_Types>(_Args)...);
        this->_Has_value = true;
        return this->_Value;
    }

    template <class _Ty2>
    void _Assign(_Ty2&& _Right) { // assign / initialize the contained value from _Right
        if (this->_Has_value) {
            this->_Value = _STD forward<_Ty2>(_Right);
        } else {
            _Construct(_STD forward<_Ty2>(_Right));
        }
    }

    template <class _Self>
    void _Construct_from(_Self&& _Right) _NOEXCEPT_COND(is_nothrow_constructible_v<_Ty,
        decltype((_STD forward<_Self>(_Right)._Value))>) { // initialize contained value from _Right iff it contains a
                                                           // value
        if (_Right._Has_value) {
            _Construct(_STD forward<_Self>(_Right)._Value);
        }
    }

    template <class _Self>
    void _Assign_from(_Self&& _Right) _NOEXCEPT_COND(
        is_nothrow_constructible_v<_Ty, decltype((_STD forward<_Self>(_Right)._Value))>&& is_nothrow_assignable_v<_Ty&,
            decltype((_STD forward<_Self>(_Right)._Value))>) { // assign/initialize/destroy contained value from _Right
        if (_Right._Has_value) {
            _Assign(_STD forward<_Self>(_Right)._Value);
        } else {
            this->reset();
        }
    }

    constexpr _Ty& _Get() & noexcept {
        return this->_Value;
    }
    constexpr const _Ty& _Get() const& noexcept {
        return this->_Value;
    }
};

// CLASS TEMPLATE optional [optional.object]
template <class _Ty>
class optional : private _SMF_control<_Optional_construct_base<_Ty>, _Ty> { // optional for object types
private:
    using _Mybase = _SMF_control<_Optional_construct_base<_Ty>, _Ty>;

public:
    static_assert(!is_reference_v<_Ty>, "T in optional<T> cannot be a reference type (N4659 23.6.2 [optional.syn]/1).");
    static_assert(!is_same_v<remove_cv_t<_Ty>, nullopt_t>,
        "T in optional<T> cannot be nullopt_t (N4659 23.6.2 [optional.syn]/1).");
    static_assert(!is_same_v<remove_cv_t<_Ty>, in_place_t>,
        "T in optional<T> cannot be in_place_t (N4659 23.6.2 [optional.syn]/1).");
    static_assert(is_reference_v<_Ty> || is_object_v<_Ty>,
        "T in optional<T> must be an object type (N4659 23.6.3 [optional.optional]/3).");
    static_assert(is_destructible_v<_Ty> && !is_array_v<_Ty>,
        "T in optional<T> must satisfy the requirements of Destructible (N4659 23.6.3 [optional.optional]/3).");

    using value_type = _Ty;

    // constructors [optional.object.ctor]
    constexpr optional() noexcept : _Mybase{} { // initialize to empty state
    }
    constexpr optional(nullopt_t) noexcept : _Mybase{} { // initialize to empty state
    }

    template <class... _Types, class = enable_if_t<is_constructible_v<_Ty, _Types...>>>
    constexpr explicit optional(in_place_t, _Types&&... _Args)
        : _Mybase(in_place, _STD forward<_Types>(_Args)...) { // initialize contained value from _Args...
    }

    template <class _Elem, class... _Types,
        class = enable_if_t<is_constructible_v<_Ty, initializer_list<_Elem>&, _Types...>>>
    constexpr explicit optional(in_place_t, initializer_list<_Elem> _Ilist, _Types&&... _Args)
        : _Mybase(
              in_place, _Ilist, _STD forward<_Types>(_Args)...) { // initialize contained value from _Ilist and _Args...
    }

    template <class _Ty2>
    using _AllowDirectConversion = bool_constant<conjunction_v<negation<is_same<_Remove_cvref_t<_Ty2>, optional>>,
        negation<is_same<_Remove_cvref_t<_Ty2>, in_place_t>>, is_constructible<_Ty, _Ty2>>>;
    template <class _Ty2                                                                         = _Ty,
        enable_if_t<conjunction_v<_AllowDirectConversion<_Ty2>, is_convertible<_Ty2, _Ty>>, int> = 0>
    constexpr optional(_Ty2&& _Right)
        : _Mybase(in_place, _STD forward<_Ty2>(_Right)) { // initialize contained value from _Right
    }
    template <class _Ty2                                                                                   = _Ty,
        enable_if_t<conjunction_v<_AllowDirectConversion<_Ty2>, negation<is_convertible<_Ty2, _Ty>>>, int> = 0>
    constexpr explicit optional(_Ty2&& _Right)
        : _Mybase(in_place, _STD forward<_Ty2>(_Right)) { // initialize contained value from _Right
    }

    template <class _Ty2>
    struct _AllowUnwrapping : bool_constant<!disjunction_v<is_same<_Ty, _Ty2>, is_constructible<_Ty, optional<_Ty2>&>,
                                  is_constructible<_Ty, const optional<_Ty2>&>,
                                  is_constructible<_Ty, const optional<_Ty2>>, is_constructible<_Ty, optional<_Ty2>>,
                                  is_convertible<optional<_Ty2>&, _Ty>, is_convertible<const optional<_Ty2>&, _Ty>,
                                  is_convertible<const optional<_Ty2>, _Ty>, is_convertible<optional<_Ty2>, _Ty>>> {};

    template <class _Ty2, enable_if_t<conjunction_v<_AllowUnwrapping<_Ty2>, is_constructible<_Ty, const _Ty2&>,
                                          is_convertible<const _Ty2&, _Ty>>,
                              int> = 0>
    optional(const optional<_Ty2>& _Right) { // possibly initialize contained value from _Right
        if (_Right) {
            this->_Construct(*_Right);
        }
    }
    template <class _Ty2, enable_if_t<conjunction_v<_AllowUnwrapping<_Ty2>, is_constructible<_Ty, const _Ty2&>,
                                          negation<is_convertible<const _Ty2&, _Ty>>>,
                              int> = 0>
    explicit optional(const optional<_Ty2>& _Right) { // possibly initialize contained value from _Right
        if (_Right) {
            this->_Construct(*_Right);
        }
    }

    template <class _Ty2,
        enable_if_t<conjunction_v<_AllowUnwrapping<_Ty2>, is_constructible<_Ty, _Ty2>, is_convertible<_Ty2, _Ty>>,
            int> = 0>
    optional(optional<_Ty2>&& _Right) { // possibly initialize contained value from _Right
        if (_Right) {
            this->_Construct(_STD move(*_Right));
        }
    }
    template <class _Ty2, enable_if_t<conjunction_v<_AllowUnwrapping<_Ty2>, is_constructible<_Ty, _Ty2>,
                                          negation<is_convertible<_Ty2, _Ty>>>,
                              int> = 0>
    explicit optional(optional<_Ty2>&& _Right) { // possibly initialize contained value from _Right
        if (_Right) {
            this->_Construct(_STD move(*_Right));
        }
    }

    // assignment [optional.object.assign]
    optional& operator=(nullopt_t) noexcept { // destroy any contained value and transition to empty state
        reset();
        return *this;
    }

    template <class _Ty2 = _Ty, class = enable_if_t<conjunction_v<negation<is_same<optional, _Remove_cvref_t<_Ty2>>>,
                                    negation<conjunction<is_scalar<_Ty>, is_same<_Ty, decay_t<_Ty2>>>>,
                                    is_constructible<_Ty, _Ty2>, is_assignable<_Ty&, _Ty2>>>>
    optional& operator=(_Ty2&& _Right) { // assign/initialize contained value from _Right
        this->_Assign(_STD forward<_Ty2>(_Right));
        return *this;
    }

    template <class _Ty2>
    struct _AllowUnwrappingAssignment
        : bool_constant<!disjunction_v<is_same<_Ty, _Ty2>, is_assignable<_Ty&, optional<_Ty2>&>,
              is_assignable<_Ty&, const optional<_Ty2>&>, is_assignable<_Ty&, const optional<_Ty2>>,
              is_assignable<_Ty&, optional<_Ty2>>>> {};

    template <class _Ty2, class = enable_if_t<conjunction_v<_AllowUnwrappingAssignment<_Ty2>,
                              is_constructible<_Ty, const _Ty2&>, is_assignable<_Ty&, const _Ty2&>>>>
    optional& operator=(const optional<_Ty2>& _Right) { // assign/initialize/destroy contained value from _Right
        if (_Right) {
            this->_Assign(*_Right);
        } else {
            reset();
        }

        return *this;
    }

    template <class _Ty2, class = enable_if_t<conjunction_v<_AllowUnwrappingAssignment<_Ty2>,
                              is_constructible<_Ty, _Ty2>, is_assignable<_Ty&, _Ty2>>>>
    optional& operator=(optional<_Ty2>&& _Right) { // assign/initialize/destroy contained value from _Right
        if (_Right) {
            this->_Assign(_STD move(*_Right));
        } else {
            reset();
        }

        return *this;
    }

    template <class... _Types>
    _Ty& emplace(_Types&&... _Args) { // destroy any contained value, then initialize from _Args...
        reset();
        return this->_Construct(_STD forward<_Types>(_Args)...);
    }

    template <class _Elem, class... _Types,
        class = enable_if_t<is_constructible_v<_Ty, initializer_list<_Elem>&, _Types...>>>
    _Ty& emplace(initializer_list<_Elem> _Ilist,
        _Types&&... _Args) { // destroy any contained value, then initialize from _Ilist and _Args...
        reset();
        return this->_Construct(_Ilist, _STD forward<_Types>(_Args)...);
    }

    // swap [optional.object.swap]
    void swap(optional& _Right) _NOEXCEPT_COND(
        is_nothrow_move_constructible_v<_Ty>&& is_nothrow_swappable_v<_Ty>) { // exchange state with _Right
        static_assert(is_move_constructible_v<_Ty>,
            "optional<T>::swap requires T to be move constructible (N4659 23.6.3.4 [optional.swap]/1).");
        static_assert(!is_move_constructible_v<_Ty> || is_swappable_v<_Ty>,
            "optional<T>::swap requires T to be swappable (N4659 23.6.3.4 [optional.swap]/1).");
        _Swap(_Right, _Is_trivially_swappable<_Ty>{});
    }

    // observers [optional.object.observe]
    _NODISCARD constexpr const _Ty* operator->() const { // return pointer to contained value
        return _STD addressof(this->_Get());
    }
    _NODISCARD constexpr _Ty* operator->() { // return pointer to contained value
        return _STD addressof(this->_Get());
    }

    _NODISCARD constexpr const _Ty& operator*() const& { // return reference to contained value
        return this->_Get();
    }
    _NODISCARD constexpr _Ty& operator*() & { // return reference to contained value
        return this->_Get();
    }
    _NODISCARD constexpr _Ty&& operator*() && { // return reference to contained value
        return _STD move(this->_Get());
    }
    _NODISCARD constexpr const _Ty&& operator*() const&& { // return reference to contained value
        return _STD move(this->_Get());
    }

    constexpr explicit operator bool() const noexcept { // return true iff *this contains a value
        return this->_Has_value;
    }
    _NODISCARD constexpr bool has_value() const noexcept { // return true iff *this contains a value
        return this->_Has_value;
    }

    _NODISCARD constexpr const _Ty& value() const& { // return reference to contained value or throw if none
        if (!has_value()) {
            _THROW(bad_optional_access{});
        }

        return this->_Get();
    }
    _NODISCARD constexpr _Ty& value() & { // return reference to contained value or throw if none
        if (!has_value()) {
            _THROW(bad_optional_access{});
        }

        return this->_Get();
    }
    _NODISCARD constexpr _Ty&& value() && { // return reference to contained value or throw if none
        if (!has_value()) {
            _THROW(bad_optional_access{});
        }

        return _STD move(this->_Get());
    }
    _NODISCARD constexpr const _Ty&& value() const&& { // return reference to contained value or throw if none
        if (!has_value()) {
            _THROW(bad_optional_access{});
        }

        return _STD move(this->_Get());
    }

    template <class _Ty2>
    _NODISCARD constexpr _Ty value_or(_Ty2&& _Right) const& { // return contained value or _Right if none
        static_assert(is_copy_constructible_v<_Ty>,
            "The const overload of optional<T>::value_or requires T to be copy constructible "
            "(N4659 23.6.3.5 [optional.observe]/18).");
        static_assert(is_convertible_v<_Ty2, _Ty>,
            "optional<T>::value_or(U) requires U to be convertible to T (N4659 23.6.3.5 [optional.observe]/18).");

        if (has_value()) {
            return this->_Get();
        }

        return static_cast<_Ty>(_STD forward<_Ty2>(_Right));
    }
    template <class _Ty2>
    _NODISCARD constexpr _Ty value_or(_Ty2&& _Right) && { // return contained value or _Right if none
        static_assert(is_move_constructible_v<_Ty>,
            "The rvalue overload of optional<T>::value_or requires T to be move constructible "
            "(N4659 23.6.3.5 [optional.observe]/20).");
        static_assert(is_convertible_v<_Ty2, _Ty>,
            "optional<T>::value_or(U) requires U to be convertible to T (N4659 23.6.3.5 [optional.observe]/20).");

        if (has_value()) {
            return _STD move(this->_Get());
        }

        return static_cast<_Ty>(_STD forward<_Ty2>(_Right));
    }

    // modifiers [optional.object.mod]
    using _Mybase::reset;

private:
    void _Swap(optional& _Right, true_type) { // implement trivial swap
        using _TrivialBaseTy = _Optional_destruct_base<_Ty>;
        _STD swap(static_cast<_TrivialBaseTy&>(*this), static_cast<_TrivialBaseTy&>(_Right));
    }

    void _Swap(optional& _Right, false_type) { // implement non-trivial swap
        const bool _Engaged = has_value();
        if (_Engaged == _Right.has_value()) {
            if (_Engaged) {
                _Swap_adl(**this, *_Right);
            }
        } else {
            optional& _Source = _Engaged ? *this : _Right;
            optional& _Target = _Engaged ? _Right : *this;
            _Target._Construct(_STD move(*_Source));
            _Source.reset();
        }
    }
};

template <class _Ty>
optional(_Ty)->optional<_Ty>;

// RELATIONAL OPERATORS [optional.relops]
template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator==(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) {
    const bool _Left_has_value = _Left.has_value();
    return _Left_has_value == _Right.has_value() && (!_Left_has_value || *_Left == *_Right);
}

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator!=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) {
    const bool _Left_has_value = _Left.has_value();
    return _Left_has_value != _Right.has_value() || (_Left_has_value && *_Left != *_Right);
}

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator<(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) {
    return _Right.has_value() && (!_Left.has_value() || *_Left < *_Right);
}

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator>(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) {
    return _Left.has_value() && (!_Right.has_value() || *_Left > *_Right);
}

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator<=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) {
    return !_Left.has_value() || (_Right.has_value() && *_Left <= *_Right);
}

template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator>=(const optional<_Ty1>& _Left, const optional<_Ty2>& _Right) {
    return !_Right.has_value() || (_Left.has_value() && *_Left >= *_Right);
}

// COMPARISONS WITH nullopt [optional.nullops]
template <class _Ty>
_NODISCARD constexpr bool operator==(const optional<_Ty>& _Left, nullopt_t) noexcept {
    return !_Left.has_value();
}
template <class _Ty>
_NODISCARD constexpr bool operator==(nullopt_t, const optional<_Ty>& _Right) noexcept {
    return !_Right.has_value();
}

template <class _Ty>
_NODISCARD constexpr bool operator!=(const optional<_Ty>& _Left, nullopt_t) noexcept {
    return _Left.has_value();
}
template <class _Ty>
_NODISCARD constexpr bool operator!=(nullopt_t, const optional<_Ty>& _Right) noexcept {
    return _Right.has_value();
}

template <class _Ty>
_NODISCARD constexpr bool operator<(const optional<_Ty>&, nullopt_t) noexcept {
    return false;
}
template <class _Ty>
_NODISCARD constexpr bool operator<(nullopt_t, const optional<_Ty>& _Right) noexcept {
    return _Right.has_value();
}

template <class _Ty>
_NODISCARD constexpr bool operator<=(const optional<_Ty>& _Left, nullopt_t) noexcept {
    return !_Left.has_value();
}
template <class _Ty>
_NODISCARD constexpr bool operator<=(nullopt_t, const optional<_Ty>&) noexcept {
    return true;
}

template <class _Ty>
_NODISCARD constexpr bool operator>(const optional<_Ty>& _Left, nullopt_t) noexcept {
    return _Left.has_value();
}
template <class _Ty>
_NODISCARD constexpr bool operator>(nullopt_t, const optional<_Ty>&) noexcept {
    return false;
}

template <class _Ty>
_NODISCARD constexpr bool operator>=(const optional<_Ty>&, nullopt_t) noexcept {
    return true;
}
template <class _Ty>
_NODISCARD constexpr bool operator>=(nullopt_t, const optional<_Ty>& _Right) noexcept {
    return !_Right.has_value();
}

// COMPARISONS WITH T [optional.comp_with_t]
template <class _Lhs, class _Rhs, class = void>
struct _Are_comparable_with_equal : false_type {};

template <class _Lhs, class _Rhs>
struct _Are_comparable_with_equal<_Lhs, _Rhs,
    void_t<decltype(_STD declval<const _Lhs&>() == _STD declval<const _Rhs&>())>>
    : is_convertible<decltype(_STD declval<const _Lhs&>() == _STD declval<const _Rhs&>()), bool>::type {};

template <class _Lhs, class _Rhs, class = void>
struct _Are_comparable_with_not_equal : false_type {};

template <class _Lhs, class _Rhs>
struct _Are_comparable_with_not_equal<_Lhs, _Rhs,
    void_t<decltype(_STD declval<const _Lhs&>() != _STD declval<const _Rhs&>())>>
    : is_convertible<decltype(_STD declval<const _Lhs&>() != _STD declval<const _Rhs&>()), bool>::type {};

template <class _Lhs, class _Rhs, class = void>
struct _Are_comparable_with_less : false_type {};

template <class _Lhs, class _Rhs>
struct _Are_comparable_with_less<_Lhs, _Rhs,
    void_t<decltype(_STD declval<const _Lhs&>() < _STD declval<const _Rhs&>())>>
    : is_convertible<decltype(_STD declval<const _Lhs&>() < _STD declval<const _Rhs&>()), bool>::type {};

template <class _Lhs, class _Rhs, class = void>
struct _Are_comparable_with_less_equal : false_type {};

template <class _Lhs, class _Rhs>
struct _Are_comparable_with_less_equal<_Lhs, _Rhs,
    void_t<decltype(_STD declval<const _Lhs&>() <= _STD declval<const _Rhs&>())>>
    : is_convertible<decltype(_STD declval<const _Lhs&>() <= _STD declval<const _Rhs&>()), bool>::type {};

template <class _Lhs, class _Rhs, class = void>
struct _Are_comparable_with_greater : false_type {};

template <class _Lhs, class _Rhs>
struct _Are_comparable_with_greater<_Lhs, _Rhs,
    void_t<decltype(_STD declval<const _Lhs&>() > _STD declval<const _Rhs&>())>>
    : is_convertible<decltype(_STD declval<const _Lhs&>() > _STD declval<const _Rhs&>()), bool>::type {};

template <class _Lhs, class _Rhs, class = void>
struct _Are_comparable_with_greater_equal : false_type {};

template <class _Lhs, class _Rhs>
struct _Are_comparable_with_greater_equal<_Lhs, _Rhs,
    void_t<decltype(_STD declval<const _Lhs&>() >= _STD declval<const _Rhs&>())>>
    : is_convertible<decltype(_STD declval<const _Lhs&>() >= _STD declval<const _Rhs&>()), bool>::type {};

template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator==(const optional<_Ty1>& _Left, const _Ty2& _Right) {
    return _Left ? *_Left == _Right : false;
}
template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator==(const _Ty1& _Left, const optional<_Ty2>& _Right) {
    return _Right ? _Left == *_Right : false;
}

template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_not_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator!=(const optional<_Ty1>& _Left, const _Ty2& _Right) {
    return _Left ? *_Left != _Right : true;
}
template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_not_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator!=(const _Ty1& _Left, const optional<_Ty2>& _Right) {
    return _Right ? _Left != *_Right : true;
}

template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_less<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator<(const optional<_Ty1>& _Left, const _Ty2& _Right) {
    return _Left ? *_Left < _Right : true;
}
template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_less<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator<(const _Ty1& _Left, const optional<_Ty2>& _Right) {
    return _Right ? _Left < *_Right : false;
}

template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_less_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator<=(const optional<_Ty1>& _Left, const _Ty2& _Right) {
    return _Left ? *_Left <= _Right : true;
}
template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_less_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator<=(const _Ty1& _Left, const optional<_Ty2>& _Right) {
    return _Right ? _Left <= *_Right : false;
}

template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_greater<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator>(const optional<_Ty1>& _Left, const _Ty2& _Right) {
    return _Left ? *_Left > _Right : false;
}
template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_greater<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator>(const _Ty1& _Left, const optional<_Ty2>& _Right) {
    return _Right ? _Left > *_Right : true;
}

template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_greater_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator>=(const optional<_Ty1>& _Left, const _Ty2& _Right) {
    return _Left ? *_Left >= _Right : false;
}
template <class _Ty1, class _Ty2, enable_if_t<_Are_comparable_with_greater_equal<_Ty1, _Ty2>::value, int> = 0>
_NODISCARD constexpr bool operator>=(const _Ty1& _Left, const optional<_Ty2>& _Right) {
    return _Right ? _Left >= *_Right : true;
}

// FUNCTION TEMPLATE swap [optional.specalg]
template <class _Ty, class = enable_if_t<is_move_constructible_v<_Ty> && is_swappable_v<_Ty>>>
inline void swap(optional<_Ty>& _Left, optional<_Ty>& _Right)
    _NOEXCEPT_COND(noexcept(_Left.swap(_Right))) { // exchange the values of _Left and _Right
    _Left.swap(_Right);
}

// FUNCTION TEMPLATE make_optional [optional.specalg]
template <class _Ty>
_NODISCARD constexpr optional<decay_t<_Ty>> make_optional(_Ty&& _Value) { // Construct an optional from _Value
    return optional<decay_t<_Ty>>{_STD forward<_Ty>(_Value)};
}
template <class _Ty,
    class... _Types>
_NODISCARD constexpr optional<_Ty> make_optional(_Types&&... _Args) { // Construct an optional from _Args
    return optional<_Ty>{in_place, _STD forward<_Types>(_Args)...};
}
template <class _Ty, class _Elem, class... _Types>
_NODISCARD constexpr optional<_Ty> make_optional(
    initializer_list<_Elem> _Ilist, _Types&&... _Args) { // Construct an optional from _Ilist and _Args
    return optional<_Ty>{in_place, _Ilist, _STD forward<_Types>(_Args)...};
}

// STRUCT TEMPLATE SPECIALIZATION hash [optional.hash]
template <class _Ty>
struct hash<optional<_Ty>>
    : _Conditionally_enabled_hash<optional<_Ty>,
          is_default_constructible_v<hash<remove_const_t<_Ty>>>> { // hash functor for optional<_Ty>
    static size_t _Do_hash(const optional<_Ty>& _Opt)
        _NOEXCEPT_COND(_Is_nothrow_hashable<remove_const_t<_Ty>>::value) { // strengthened
        constexpr size_t _Unspecified_value = 0;

        if (_Opt) {
            return hash<remove_const_t<_Ty>>{}(*_Opt);
        }

        return _Unspecified_value;
    }
};

_STD_END

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv
#pragma message("class template optional is only available with C++17 or later.")
#endif // _HAS_CXX17
#endif // RC_INVOKED
#endif // _OPTIONAL_
